/*
 * Copyright (C) 2005-2015 Alfresco Software Limited.
 *
 * This file is part of Alfresco
 *
 * Alfresco is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Alfresco is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 */
package org.springframework.extensions.directives;

import java.io.IOException;
import java.io.StringWriter;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.extensions.surf.DependencyAggregator;
import org.springframework.extensions.surf.extensibility.DeferredContentTargetModelElement;
import org.springframework.extensions.surf.extensibility.ExtensibilityDirectiveData;
import org.springframework.extensions.surf.extensibility.ExtensibilityModel;

import freemarker.core.Environment;
import freemarker.template.TemplateDirectiveBody;
import freemarker.template.TemplateException;
import freemarker.template.TemplateModelException;

/**
 * <p>This FreeMarker directive should be used to add raw JavaScript. As well as ensuring that the correct script blocks are output
 * it also allows JavaScript to be relocated to other locations within the {@link ExtensibilityModel} via the {@link RelocateJavaScriptOutputDirective}
 * which enables WebScripts to ensure that all JavaScript appears at the end of an HTML page as is recommended for optimum performance.
 * It also ensures that raw JavaScript inserts are placed correctly within aggregated JavaScript resource files (generated by the 
 * {@link DependencyAggregator} service) via the group attribute.</p>
 * 
 * @author David Draper
 */
public class AddInlineJavaScriptDirective extends JavaScriptDependencyDirective
{
    private static final Log logger = LogFactory.getLog(AddInlineJavaScriptDirective.class);
    
    public AddInlineJavaScriptDirective(String directiveName, ExtensibilityModel model)
    {
        super(directiveName, model);
    }

    /**
     * Overridden to prevent the "src" attribute not specified when running in legacy mode. 
     */
    @SuppressWarnings("rawtypes")
    @Override
    protected void addLegacyDependencyRequest(Map params) throws TemplateModelException
    {
        // No action required.
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    @Override
    public ExtensibilityDirectiveData createExtensibilityDirectiveData(String id, 
                                                                       String action, 
                                                                       String target,
                                                                       Map params, 
                                                                       TemplateDirectiveBody body, 
                                                                       Environment env) throws TemplateException
    {
        // Render the body (i.e. the actual inline JavaScript code) into a StringWriter and then use that
        // along with the inline marker to construct a fake dependency. This should 
        StringWriter o = new StringWriter();
        try
        {
            body.render(o);
        }
        catch (IOException e)
        {
            // Hopefully we shouldn't have a problem rendering the body. It's unlikely we'd have made it this
            // far if we would. But we will generate an error just in case...
            logger.error("The following exception occurred processing the body of an inline JavaScript request: ", e);
        }
        
        String dependency = DependencyAggregator.INLINE_AGGREGATION_MARKER + o.toString(); 
        
        // Get the group;
        String group = getStringProperty(params, DirectiveConstants.GROUP_PARAM, false); // null is acceptable as a group (it is effectively the default group)
            
        DeferredContentTargetModelElement targetElement = getModel().getDeferredContent(OutputJavaScriptDirective.OUTPUT_DEPENDENCY_DIRECTIVE_ID, OutputJavaScriptDirective.OUTPUT_JS_DEPENDENCIES_DIRECTIVE_NAME);
        DependencyDirectiveData directiveData = new DependencyDirectiveData(id, 
                                                                            action, 
                                                                            target, 
                                                                            getDirectiveName(), 
                                                                            body, 
                                                                            env, 
                                                                            dependency, 
                                                                            group,
                                                                            getWebFrameworkConfig().isAggregateDependenciesEnabled(),
                                                                            targetElement);
        return directiveData;
    }
}
